package model.valuemap;

import java.util.LinkedList;
import java.util.List;

import model.virtualmap.OccupancyMap;

public class ValueMap {

	private Integer[][] grid;
	private OccupancyMap map;
	private int width;
	private int height;
	private int x;
	private int y;
	
	public ValueMap(OccupancyMap map)
	{
		this.map = map;
		InitMap(map.getGrid());
	}
	
	public int getWidth()
	{
		return width;
	}
	
	public int getHeight()
	{
		return height;
	}
	
	/**
	 * Create a ValueGrid with the same width and height as the given grid
	 * @param grid
	 */
	public void InitMap(char[][] grid)
	{
		
		width = grid.length;
		height = grid[0].length;
		this.grid = new Integer[width][height];
	}
	
	/**
	 * Generates and returns a List of commands for the Robot to use
	 * @return
	 */
	public List<Integer> generatePath()
	{
		List<Integer> commands = new LinkedList<Integer>();
		int x = this.x;
		int y = this.y;
		System.out.println(x + ":" + y);
		int current = grid[x][y];
		
		int direction;
		
		while((direction = getNextDirection(x, y, current)) != -1)
		{
			System.out.println(direction);
			commands.add(direction);
			switch (direction)
			{
			case 0:
				current = grid[x][y-1];
				y--;
				break;
			case 3:
				current = grid[x+1][y];
				x++;
				break;
			case 2:
				current = grid[x][y+1];
				y++;
				break;
			case 1:
				current = grid[x-1][y];
				x--;
				break;
			}
		}
		
		return commands;
	}
	
	private int getNextDirection(int x,int y, int current)
	{
		//System.out.println("current: " + current);
		//System.out.println("top: " + grid[x][y-1] + ", right: " + grid[x+1][y] + ", bot: " + grid[x][y+1] + ", left: " + grid[x-1][y]);
		
		int direction = -1;
		int minValue = 2;
		
		if(y > 0)
			if(grid[x][y-1] < current && grid[x][y-1] > minValue)
			{
				current = grid[x][y-1];
				direction = 0;
			}
				
		if(x > 0)
			if(grid[x-1][y] < current && grid[x-1][y] > minValue)
			{
				current = grid[x-1][y];
				direction = 1;
			}
				
		if(y < height-1)
			if(grid[x][y+1] < current && grid[x][y+1] > minValue)
			{
				current = grid[x][y+1];
				direction = 2;
			}
				
		if(x < width-1)
			if(grid[x+1][y] < current && grid[x+1][y] > minValue)
			{
				current = grid[x+1][y];
				direction = 3;
			}
		System.out.println("new current: " + current);
		return direction;
	}
	
	public void generateMap(int x, int y, int wallDistance)
	{
		clearGrid();
		this.x = x;
		this.y = y;
		
		grid[x][y] = generateValue(x, y, wallDistance);
		System.out.println("Calculated Path from: " + x + "," + y);
	}
	
	private Integer generateValue(int x,int y, int wallDistance)
	{
		if(grid[x][y] != null)
			return grid[x][y];
		else if(map.getGrid()[x][y] == 'o')
			return grid[x][y] = -2;
		else if(map.getGrid()[x][y] == 'n')
			return grid[x][y] = 0;
		else
		{
			grid[x][y] = -1;  // So we know its being checked!

			if(x < width-1)
			{
				grid[x+1][y] = generateValue(x+1, y, wallDistance);
			}
			if(y > 0)
			{
				grid[x][y-1] = generateValue(x, y-1, wallDistance);
			}
			if(x > 0)
			{
				grid[x-1][y] = generateValue(x-1, y, wallDistance);
			}
			if(y < height-1)
			{
				grid[x][y+1] = generateValue(x, y+1, wallDistance);
			}
			
			int v = -1;
			if(y > 0)
			{
				if(grid[x][y-1] <= -2 && grid[x][y-1] > -2-wallDistance)
					return grid[x][y-1]-1;
				if((grid[x][y-1] >= 0 && v > grid[x][y-1]) || v < 0)
					v = grid[x][y-1];
			}
			if(y < height-1)
			{
				if(grid[x][y+1] <= -2 && grid[x][y+1] > -2-wallDistance)
					return grid[x][y+1]-1;
				if((grid[x][y+1] >= 0 && v > grid[x][y+1]) || v < 0)
					v = grid[x][y+1];
			}
			if(x > 0)
			{
				if(grid[x-1][y] <= -2 && grid[x-1][y] > -2-wallDistance)
					return grid[x-1][y]-1;
				if((grid[x-1][y] >= 0 && v > grid[x-1][y]) || v < 0)
					v = grid[x-1][y];
			}
			if(x < width-1)
			{
				if(grid[x+1][y] <= -2 && grid[x+1][y] > -2-wallDistance)
					return grid[x+1][y]-1;
				if((grid[x+1][y] >= 0 && v > grid[x+1][y]) || v < 0)
					v = grid[x+1][y];
			}
			
			return (v >= 0) ? v+1 : v;
		}
	}
	
	public void printGrid()
	{
		try{
			for(int i=0; i < width*height;i++)
			{
				if(grid[i%width][i/width] == null)
					System.out.print("|X");
				else
					System.out.print("|" + grid[i%width][i/width]);
				if(i%width == width-1)
					System.out.println();
			}
		}
		catch(Exception e)
		{
			System.err.println("PrintGrid: Is the grid initialized?");
		}
	}
	
	public void clearGrid()
	{
		try{
			int width = grid.length-1;
			int height = grid[0].length-1;
			for(int i=0; i < width*height;i++)
				grid[i%width][i/width] = null;
		}
		catch(Exception e)
		{
			System.err.println("ClearGrid: there is no grid?");
		}
	}
}
